package com.quanyue.music.file.job;

import cn.binarywang.wx.miniapp.api.WxMaMsgService;
import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage;
import com.quanyue.auto.cache.CacheService;
import com.quanyue.auto.email.domain.EmailConfig;
import com.quanyue.auto.email.domain.EmailContent;
import com.quanyue.auto.email.mapper.EmailConfigMapper;
import com.quanyue.auto.email.service.EmailService;
import com.quanyue.auto.fs.FsProperties;
import com.quanyue.auto.fs.QiniuServiceImpl;
import com.quanyue.auto.miniapp.support.MiniAppContext;
import com.quanyue.auto.util.AssertUtils;
import com.quanyue.auto.util.StringUtils;
import com.quanyue.music.domain.constant.CacheConstants;
import com.quanyue.music.domain.constant.FMPlayStatus;
import com.quanyue.music.domain.entity.*;
import com.quanyue.music.file.mapper.ListenRecordMapper;
import com.quanyue.music.system.mapper.PlayListMapper;
import com.quanyue.music.template.service.TemplateService;
import com.quanyue.music.user.mapper.ManagerLoginErrorMapper;
import com.quanyue.music.user.mapper.ShareRecordMapper;
import com.quanyue.music.user.mapper.UserMapper;
import com.quanyue.music.user.mapper.VIPMapper;
import com.quanyue.music.user.type.FmVipDetail;
import me.chanjar.weixin.common.exception.WxErrorException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import static com.quanyue.music.domain.constant.TemplateId.*;

@Component
public class FMJob {
    private final Logger log = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private CacheService cacheService;
    @Autowired
    private ListenRecordMapper listenRecordMapper;
    @Autowired
    private EmailService emailService;
    @Autowired
    private VIPMapper vipMapper;
    @Autowired
    private EmailConfigMapper configMapper;
    @Autowired
    private PlayListMapper playListMapper;
    @Autowired
    private ShareRecordMapper shareRecordMapper;
    @Autowired
    private ManagerLoginErrorMapper managerLoginErrorMapper;
    @Autowired
    private WxMaMsgService wxMaMsgService;
    @Autowired
    private TemplateService templateService;
    @Autowired
    private UserMapper userMapper;


    @Scheduled(cron = "0 0/1 * * * ?")
    public void saveVisitLog() throws IOException {
        log.info("定时任务启动");
        QiniuServiceImpl impl = new QiniuServiceImpl();
        Map <String, byte[]> map = cacheService.get(CacheConstants.FILE_CACHE.name());
        Map <String, byte[]> saveMap = new ConcurrentHashMap <>();
        saveMap.putAll(map);
        map.clear();
        Set set = saveMap.keySet();
        for (Iterator iterator = set.iterator(); iterator.hasNext();) {
            String s1 = (String) iterator.next();
            byte[] s2 = saveMap.get(s1);
            if (StringUtils.isBlank(s1)) continue;
            FsProperties properties = cacheService.get(CacheConstants.FS_PROPERTIES_CONFIG.name());
            impl.saveFile(s2, s1, properties);
        }
    }

    // 更新实时在线人数
    @Scheduled(cron = "0/5 * * * * ?")
    public void updateListenRecord() {
        listenRecordMapper.truncateAll(LocalDateTime.now());
    }

    @Scheduled(cron = "0 0/30 * * * ?")
    public void sendEmail() {
        List <EmailConfig> configList = configMapper.findAll();
        EmailConfig config;
        if (configList.size() > 0) {
            config = configList.get(0);
        } else {
            throw new AssertUtils.ValidateException("您还没有配置邮件发送人");
        }
        String[] value = new String[1];
        value[0] = config.getEmail();
        EmailContent content = new EmailContent();
        content.setTitle("温馨提醒！");
        content.setContent("请上传文件！");
        emailService.send(content);
    }

    // 更新到期会员的状态
    @Scheduled(cron = "0 0/2 * * * ?")
    public void updateVipStatus() {
        List <FmVip> fmVip = vipMapper.findAllValid();
        List <FormId> formIdList = templateService.getFormIdList();
        List <FmVip> saveVIP = new ArrayList <>();
        List <String> formIds = new ArrayList <>();
        for (FmVip vip : fmVip) {
            if (vip.getEndTime().compareTo(LocalDateTime.now()) <= 0) {
                vip.setDelFlag(true);
                saveVIP.add(vip);
            }
        }
        for (FormId formId : formIdList) {
            if (formId.getExpireTime().compareTo(LocalDateTime.now()) <= 0)
                formIds.add(formId.getId());
        }
        if (!saveVIP.isEmpty()) vipMapper.updateAll(saveVIP);
        if (!formIds.isEmpty()) templateService.delList(formIds);
    }

    // 会员到期提醒 && 第一次使用产品1/3天后通知消息
    @Scheduled(cron = "0 0 0 0/1 * ?")
//    @Scheduled(cron = "0 * * * * ?")
    public void overDueInform() {
        List <FmVipDetail> detail = vipMapper.findAllDetail();
        List <User> userList = userMapper.findAllValid();
        boolean delVip = false;
        for (User user : userList) {
            String content = null;
            List <WxMaTemplateMessage.Data> dataList = new ArrayList <>();
            long daysDiff = ChronoUnit.DAYS.between(LocalDate.from(user.getCreateTime()), LocalDate.now());
            if (daysDiff == 1) {
                content = "亲爱得，当你看到这条通知，说明你和歪果已经认识1天了";
            } else if (daysDiff == 3) {
                content = "Hi，悄悄问你个问题，你有多喜欢歪果？";
            } else {
                continue;
            }
            // 封装模板消息参数
            WxMaTemplateMessage message = this.getTemplate(user.getOpenId(), user.getId());
            if (message == null) continue;
            dataList.add(new WxMaTemplateMessage.Data("keyword1", "Wiggle FM"));
            dataList.add(new WxMaTemplateMessage.Data("keyword2", content));
            try {
                message.setData(dataList);
                message.setTemplateId(HARASS_ACCOUNTS.getTemplateId());
                message.setPage(HARASS_ACCOUNTS.getUrl());
                // 新用户72小时后推送调查问卷页面
                if (daysDiff == 3) message.setPage("pages/question/question");
                MiniAppContext.setMerchantNo(10100);
                wxMaMsgService.sendTemplateMsg(message);
            } catch (WxErrorException e) {
                throw new RuntimeException(e);
            } catch (NullPointerException e) {
                log.error("form_id: ", message.getFormId());
            }
        }
        for (FmVipDetail vip : detail) {
            String content = null;
            List <WxMaTemplateMessage.Data> dataList = new ArrayList <>();
            // 计算到期类型
            long daysDiff = ChronoUnit.DAYS.between(LocalDate.now(), LocalDate.from(vip.getEndTime()));
            if (daysDiff == 3) {
                content = "你的VIP账户快Oops！小主，你的尊贵VIP快要到期啦，给我个机会继续陪你呗~";
            } else if (daysDiff == 1) {
                content = "SOS！24小时后，歪果电台就要失去你了TAT，赶紧点我，每个月少喝一杯咖啡，就能续费陪伴~";
            } else if (daysDiff == -2) {
                content = "你收到了一条来自歪果MC的语音信息，点击查看。";
                delVip = true;
            } else {
                continue;
            }
            // 封装模板消息参数
            WxMaTemplateMessage message = this.getTemplate(vip.getOpenId(), vip.getUserId());
            if (message == null) continue;
            if (daysDiff == -2) message.setPage("pages/voice/voice");
            dataList.add(new WxMaTemplateMessage.Data("keyword1", "Wiggle FM"));
            dataList.add(new WxMaTemplateMessage.Data("keyword2", vip.getEndTime().toString()));
            dataList.add(new WxMaTemplateMessage.Data("keyword3", content));
            try {
                message.setData(dataList);
                MiniAppContext.setMerchantNo(10100);
                wxMaMsgService.sendTemplateMsg(message);
                if (delVip) vipMapper.deleteOne(vip.getId());
            } catch (WxErrorException e) {
                throw new RuntimeException(e);
            } catch (NullPointerException e) {
                log.error("form_id: ", message.getFormId());
            }
        }
    }

    @Scheduled(cron = "0 0 21 * * ?")
    public void sendMessage() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (w < 0) w = 0;
        String content = null;
        if (w == 0) {
            content = "又双叒要到周一啦T T，先别急着丧，歪果电台会24小时陪伴你。";
        } else if (w == 5) {
            content = "嘿！终于盼到双休日啦!!! 周末各种快活，千万别忘了歪果~";
        } else {
            return;
        }
        List <User> userList = userMapper.findAllValid();
        for (User user : userList) {
            List <WxMaTemplateMessage.Data> dataList = new ArrayList <>();
            // 封装模板消息参数
            WxMaTemplateMessage message = this.getTemplate(user.getOpenId(), user.getId());
            if (message == null) continue;
            dataList.add(new WxMaTemplateMessage.Data("keyword1", "Wiggle FM"));
            dataList.add(new WxMaTemplateMessage.Data("keyword2", content));
            try {
                message.setData(dataList);
                message.setTemplateId(HARASS_MISS.getTemplateId());
                message.setPage(HARASS_MISS.getUrl());
                MiniAppContext.setMerchantNo(10100);
                wxMaMsgService.sendTemplateMsg(message);
            } catch (WxErrorException e) {
                throw new RuntimeException(e);
            } catch (NullPointerException e) {
                log.error("form_id: ", message.getFormId());
            }
        }
//        new ThreadPoolExecutor().execute(Runnable);
    }

    private WxMaTemplateMessage getTemplate(String openId, String userId) {
        List <FormId> formIds = templateService.getFormId(userId);
        if (formIds.isEmpty()) return null;
        WxMaTemplateMessage message = WxMaTemplateMessage.newBuilder().build();
        message.setToUser(openId);
        message.setTemplateId(SERVER_OVER.getTemplateId());
        message.setPage(SERVER_OVER.getUrl());
        message.setFormId(formIds.get(0).getFormId());
        templateService.delOne(formIds.get(0).getId());
        return message;
    }


    // 查询当前正在播放的歌曲，更新播放状态（东部时区为准）
    @Scheduled(cron = "0 0/15 * * * ?")
    public void updatePlayStatus() {
        List <PlayList> playListsNow = playListMapper.findByTime(LocalDateTime.now());
        List <PlayList> playListsLast = playListMapper.findByTime(LocalDateTime.now().minusMinutes(30));
        if (!playListsNow.isEmpty()) {
            playListsNow.forEach(playList -> {
                playList.setStatus(FMPlayStatus.PLAY);
                log.info("已更新的播放列表ID(PLAY): {}" + playList.getId());
            });
            playListMapper.updateSelectiveAll(playListsNow);
        }
        if (!playListsLast.isEmpty()) {
            playListsLast.forEach(playLast -> {
                log.info("已更新的播放列表ID(EMMA): {}" + playLast.getId());
                playLast.setStatus(FMPlayStatus.EMMA);
            });
            playListMapper.updateSelectiveAll(playListsLast);
        }
    }

    // 取消管理员登录限制
    @Scheduled(cron = "0/30 * * * * ?")
    public void updateLoginError() {
        managerLoginErrorMapper.findAllValid().forEach(managerLoginError -> {
            if (managerLoginError.getEndTime().compareTo(LocalDateTime.now()) <= 0) {
                managerLoginError.setDelFlag(true);
                managerLoginErrorMapper.update(managerLoginError);
            }
        });
    }

    @Scheduled(cron = "0 0/3 * * * ?")
    @Transactional
    public void shareConvertVip() {
        List <ShareRecord> records = shareRecordMapper.findByValidCount();
        records.forEach(shareRecord -> {
            FmVip vip = vipMapper.findByUserIdValid(shareRecord.getIssueUser());
            int i = shareRecord.getValidCount() / 3;
            if (i > 0) {
                // 检索过期记录
                String expiredUser = vipMapper.findExpiredUser(shareRecord.getIssueUser());
                if (StringUtils.isNotBlank(expiredUser))
                    vipMapper.deleteOne(expiredUser);
                // 增加会员时长
                if (vip != null) {
                    vip.setEndTime(vip.getEndTime().plusMonths(i));
                    vipMapper.update(vip);
                } else {
                    vip = new FmVip();
                    vip.setUserId(shareRecord.getIssueUser());
                    vip.setRechargeRule("share");
                    vip.setStartTime(LocalDateTime.now());
                    vip.setEndTime(LocalDateTime.now().plusMonths(i));
                    vip.setDelFlag(false);
                    vipMapper.insert(vip);
                }
                shareRecord.setValidCount(shareRecord.getValidCount() - i * 3);
                shareRecordMapper.update(shareRecord);
                // 消息通知
                List <WxMaTemplateMessage.Data> dataList = new ArrayList <>();
                // 封装模板消息参数
                User user = userMapper.findOne(vip.getUserId());
                WxMaTemplateMessage message = this.getTemplate(user.getOpenId(), user.getId());
                if (message != null) {
                    String content = "猴塞雷！你的3位好友已成功入伙歪果，这里是你的免费VIP，请查收~";
                    dataList.add(new WxMaTemplateMessage.Data("keyword1", "成功"));
                    dataList.add(new WxMaTemplateMessage.Data("keyword2", String.valueOf(i) + "月VIP"));
                    dataList.add(new WxMaTemplateMessage.Data("keyword3", String.valueOf(i * 3)));
                    dataList.add(new WxMaTemplateMessage.Data("keyword4", LocalDateTime.now().toString()));
                    dataList.add(new WxMaTemplateMessage.Data("keyword5", content));
                    try {
                        message.setData(dataList);
                        message.setTemplateId(INVITE_RESULT.getTemplateId());
                        message.setPage(INVITE_RESULT.getUrl());
                        MiniAppContext.setMerchantNo(10100);
                        wxMaMsgService.sendTemplateMsg(message);
                    } catch (WxErrorException e) {
                        throw new RuntimeException(e);
                    } catch (NullPointerException e) {
                        log.error("form_id: ", message.getFormId());
                    }
                }
            }
        });
    }
}

